package seismosurfer.layer;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JMenuItem;
import javax.swing.JSeparator;

import seismosurfer.data.QuakeClientData;
import seismosurfer.data.QuakeData;
import seismosurfer.graphics.SeismoDrawingAttributes;
import seismosurfer.graphics.SeismoPoint;
import seismosurfer.gui.menuitem.AddDocumentMenuItem;
import seismosurfer.gui.panel.QuakeAttributesPanel;
import seismosurfer.http.HttpGateway;

import com.bbn.openmap.event.LayerStatusEvent;
import com.bbn.openmap.event.MapMouseEvent;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.util.SwingWorker;

/**
 * An extension to the SeismoLayer for the earthquake data. 
 *
 */
public class QuakeLayer extends SeismoLayer {
    
    private static final long serialVersionUID = -3093138917625950013L;

    MacroseismicLayer macroLayer = null;

    public QuakeLayer() {
        super();
    }
    
    /**
     * Fetches the earthquake data that satisfy a query and 
     * visualizes them on the map through this layer.
     * 
     * @param queryName the name of the query
     * @param parameters the name/value pairs of the parameters
     */
    public void loadQuakeClientData(final String queryName, final Map parameters) {

        final SwingWorker worker = new SwingWorker() {

            public Object construct() {
                fireRequestInfoLine(updateInfoLine);
                fireStatusUpdate(LayerStatusEvent.START_WORKING);

                // Clean macroseismic layer
                if (macroLayer != null) {
                    if (macroLayer.getList() != null) {
                        macroLayer.getList().clear();
                        macroLayer.doPrepare();
                    }
                } else {
                    System.out.println("MacroLayer NULL!");
                }

                HttpGateway.loadQuakeClientData(queryName, parameters);
                loadGraphics();

                return null;
            }

            // Runs on the event-dispatching thread.
            public void finished() {
                fireRequestInfoLine(emptyInfoLine);
                fireStatusUpdate(LayerStatusEvent.FINISH_WORKING);
            }
        };
        worker.start();

    }

    public void loadGraphics() {

        java.util.List quakes = QuakeClientData.getQuakeResults();

        OMGraphicList gr = getList();

        if (gr == null) {
            gr = new OMGraphicList(quakes.size());
        } else {
            gr.clear();
        }

        SeismoPoint point;

        for (Iterator i = quakes.iterator(); i.hasNext();) {
            QuakeData qd = (QuakeData) i.next();

            point = new SeismoPoint((float) qd.getLatitude(), (float) qd
                    .getLongitude());
            point.setAppObject(qd);

            for (Iterator it = seismoAttributesList.iterator(); it.hasNext();) {
                ((SeismoDrawingAttributes) it.next()).setTo(point);
            }

            gr.add(point);
        }

        setList(gr);

        doPrepare();
    }

    protected QuakeAttributesPanel attrPanel = null;

    public boolean leftClick(OMGraphic omg, MapMouseEvent mme) {

        if (addDocMI.isSelected()) {
            addDocMI.showRadioDlg((QuakeData) omg.getAppObject());

            return false;
        } else {

            if (getActiveMouseModeID().equals(navMouseMode)) {
                getMouseEventInterpreter().rightClick(omg, mme);
            }

            else if (getActiveMouseModeID().equals(infoMouseMode)) {

                if (attrPanel == null) {
                    attrPanel = new QuakeAttributesPanel(getName());
                }
                attrPanel.setAttributes(omg.getAppObject());
                attrPanel.showAttributesDialog(mme.getPoint());

            }
        }

        return true;

    }

    protected java.util.List graphicItems = new ArrayList();

    protected JMenuItem macroPopMI = null;

    protected JMenuItem docPopMI = null;

    protected MacroseismicListener ml = null;

    protected DocumentListener dl = null;

    public java.util.List getItemsForOMGraphicMenu(OMGraphic omg,
            MapMouseEvent mme) {

        setClickCoordinates(mme);

        if (graphicItems.isEmpty()) {
            graphicItems.addAll(getItemsForMapMenu(mme));
            graphicItems.add(new JSeparator());

            macroPopMI = new JMenuItem("Macroseismic...", KeyEvent.VK_M);
            ml = new MacroseismicListener();
            macroPopMI.addActionListener(ml);

            graphicItems.add(macroPopMI);

            docPopMI = new JMenuItem("Documents...", KeyEvent.VK_D);
            dl = new DocumentListener();
            docPopMI.addActionListener(dl);

            graphicItems.add(docPopMI);
        }

        ml.setOMGraphic(omg);
        dl.setOMGraphic(omg);

        macroPopMI.setEnabled(((QuakeData) omg.getAppObject())
                .getHasMacroseismic());

        docPopMI.setEnabled(((QuakeData) omg.getAppObject()).getHasInfo());

        return graphicItems;
    }
    
    /**
     * A listener that handles the fetching of
     * macroseismic data for a particular
     * earthquake.
     *
     */
    public class MacroseismicListener implements ActionListener {

        protected OMGraphic omg;

        public void setOMGraphic(OMGraphic omg) {
            this.omg = omg;
        }

        public void actionPerformed(ActionEvent e) {

            // Keep only the selected quake which
            // has macroseismic data to show it later...
            QuakeClientData.clear();
            QuakeClientData.getQuakeResults().add(omg.getAppObject());

            loadGraphics();

            if (macroLayer != null) {
                macroLayer.loadMacroseismicForQuake(((QuakeData) omg
                        .getAppObject()).getQuakeID());
            } else {
                System.out.println("MacroLayer NULL!");
            }

        }

    }
    
    /**
     * A listener that handles the display of
     * documents for a particular earthquake.
     *
     */
    public class DocumentListener implements ActionListener {

        protected OMGraphic omg;

        public void setOMGraphic(OMGraphic omg) {
            this.omg = omg;
        }

        public void actionPerformed(ActionEvent e) {

            HttpGateway.showDocument(((QuakeData) omg.getAppObject())
                    .getQuakeID());

        }

    }

    public String getToolTipTextFor(OMGraphic omg) {

        if (getActiveMouseModeID().equals(infoMouseMode)) {
            return "Mag : " + ((QuakeData) omg.getAppObject()).getMagnitude();
        }

        return null;
    }

    public boolean isHighlightable(OMGraphic omg) {
        boolean highlight = false;

        if (getActiveMouseModeID().equals(infoMouseMode)) {
            return highlight = true;
        }

        else if (getActiveMouseModeID().equals(navMouseMode)) {

            if (((QuakeData) omg.getAppObject()).getHasMacroseismic()
                    || ((QuakeData) omg.getAppObject()).getHasInfo()) {
                return highlight = true;
            }
        }

        return highlight;
    }

    protected AddDocumentMenuItem addDocMI = null;

    public void findAndInit(Object someObj) {

        super.findAndInit(someObj);

        if (someObj instanceof AddDocumentMenuItem) {
            addDocMI = (AddDocumentMenuItem) someObj;

            System.out.println("AddDocumentMenuItem found!!!");
        }

        if (someObj instanceof MacroseismicLayer) {
            macroLayer = (MacroseismicLayer) someObj;
        }

        if (attrPanel == null) {
            attrPanel = new QuakeAttributesPanel(getName());
        }
        attrPanel.findAndInit(someObj);
    }

    public void findAndUndo(Object someObj) {
        super.findAndUndo(someObj);
    }

}
